using System.Threading;
using PaulRz.Util.Patterns;

namespace PaulRz.Util.Patterns
{
    /// <summary>
    /// The abstraction of the thread
    /// </summary>
    public abstract class ActiveObject : IRunnable
    {
        protected int joinTime = 1000;
        protected Thread thread;
        protected bool isStopping = false;

        private string name;
        
        /// <summary>
        /// Get or Set the name of the active object
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        
        protected ActiveObject(string name)
        {
            this.name = name;
        }
        
        protected ActiveObject(string name, int joinTime) : this(name)
        {
            this.joinTime = joinTime;
        }

        protected ActiveObject(string name, ILogInterface logger, int joinTime)
            : this(name, joinTime)
        {
            this.logger = logger;
        }

        private ILogInterface logger = null;
        private bool isBackground = true;

        protected ILogInterface Logger
        {
            get
            {
                if (logger == null)
                    logger = FakeLogger.Default;
                
                return logger;
            }
        }

        /// <summary>
        /// Get or Set if the object is in background mode
        /// </summary>
        public bool IsBackground
        {
            get { return isBackground; }
            set { isBackground = value; }
        }

        /// <summary>
        /// Get if the object is stopping
        /// </summary>
        public bool IsStopping
        {
            get { return isStopping; }
        }

        /// <summary>
        /// Get if the object has been stopped
        /// </summary>
        public bool Stopped
        {
            get
            {
                if (thread != null)
                    return !thread.IsAlive;
                else 
                    return true;
            }
        }

        /// <summary>
        /// Starts the activity of the object
        /// </summary>
        public virtual void Start()
        {
            if (thread==null || !thread.IsAlive)
            {
                thread = new Thread(new ThreadStart(Run));
                thread.Name = name;
                thread.IsBackground = IsBackground;
            }
            isStopping = false;
            thread.Start();
        }
        
        /// <summary>
        /// The main working thread.
        /// Shouldn't throw any exception if it's not intended to crash the process.
        /// </summary>
        protected abstract void Run();

        /// <summary>
        /// Stops the activity of the object
        /// </summary>
        public virtual void Stop()
        {
            if (isStopping || thread==null || !thread.IsAlive)
                return;

            isStopping = true;
            
            if (!thread.Join(joinTime))
                thread.Abort();

            thread = null;
        }
        
        /// <summary>
        /// The name of the active object
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name;
        }
        
        /// <summary>
        /// Get the hash code
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return Name.GetHashCode();
        }
    }
}
